import mx.utils.Delegate;

import gugga.sequence.PreconditionsTask;
import gugga.sequence.PreconditionsManager;
import gugga.sequence.IPreconditionsManager;
import gugga.sequence.FictiveTask;
import gugga.common.EventDescriptor;
import gugga.common.ITask;

import guggaLibTests.support.TaskExecutionEvaluator;

import test_framework.test.unit.TestCase;

/**
 * @author vladimir
 */
class guggaLibTests.PreconditionsTaskTest
		extends TestCase
{
	private var delayInterval:Number;
	
	public function PreconditionsTaskTest()
	{
		super();
		this.delayInterval = 1000;
	}
	
	public function testStartWithoutPreconditions()
	{
		// initialize TaskExecutionEvaluator object:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		evaluator.setDelayedEvaluation(this.delayInterval);
		
		var isAccepting:Boolean = true;
		var preconditionsManager:IPreconditionsManager 
			= new PreconditionsManager(isAccepting);
		
		// initialize PreconditionsTask with preconditionsManager:
		var preconditionsTask:ITask 
			= new PreconditionsTask(preconditionsManager);
		
		preconditionsTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		preconditionsTask.addEventListener(
				"completed", 
				Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		preconditionsTask.start();
		
		// there are no preconditions added, so the preconditionsTask should be 
		// completed right after its start:
		evaluator.registerRequiredTaskStatus({task:preconditionsTask, event:"start"});
		evaluator.registerRequiredTaskStatus({task:preconditionsTask, event:"completed"});
				
		evaluator.pauseToEvaluateTaskExecution();
	}
	
	public function testNotCompletedWhenNotStartedPreconditionsMetBeforeInitialization()
	{
		// initialize TaskExecutionEvaluator object:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		
		var isAccepting:Boolean = true;
		var preconditionsManager:IPreconditionsManager 
			= new PreconditionsManager(isAccepting);
		
		var eventSource1:FictiveTask = new FictiveTask();
		var precondition1:EventDescriptor = new EventDescriptor(
				eventSource1, 
				"start");
		preconditionsManager.add(precondition1);
		
		var eventSource2:FictiveTask = new FictiveTask();
		var precondition2:EventDescriptor = new EventDescriptor(
				eventSource2, 
				"start");
		preconditionsManager.add(precondition2);
		
		// meet preconditions before PreconditionsTask initialization:
		eventSource1.start();
		eventSource2.start();
		
		// initialize PreconditionsTask with preconditionsManager:
		var preconditionsTask:ITask 
			= new PreconditionsTask(preconditionsManager);
		
		preconditionsTask.addEventListener(
				"completed", 
				Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		evaluator.assertTaskStatusRegisterIsEmpty("preconditionsTask should not be completed, because it's not started yet, despite preconditions were met before its instanciation");
	}
	
	public function testNotCompletedWhenNotStartedPreconditionsMetAfterInitialization()
	{
		// initialize TaskExecutionEvaluator object:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		
		var isAccepting:Boolean = true;
		var preconditionsManager:IPreconditionsManager 
			= new PreconditionsManager(isAccepting);
		
		var eventSource1:FictiveTask = new FictiveTask();
		var precondition1:EventDescriptor = new EventDescriptor(
				eventSource1, 
				"start");
		preconditionsManager.add(precondition1);
		
		var eventSource2:FictiveTask = new FictiveTask();
		var precondition2:EventDescriptor = new EventDescriptor(
				eventSource2, 
				"start");
		preconditionsManager.add(precondition2);
		
		// initialize PreconditionsTask with preconditionsManager:
		var preconditionsTask:ITask 
			= new PreconditionsTask(preconditionsManager);
		
		preconditionsTask.addEventListener(
				"completed", 
				Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		// meet preconditions after PreconditionsTask initialization:
		eventSource1.start();
		eventSource2.start();
		
		evaluator.assertTaskStatusRegisterIsEmpty("preconditionsTask should not be completed, because it's not started yet, despite preconditions were met after its instanciation");
	}
	
	public function testCompletedWhenStartedPreconditionsMetBeforeInitialization()
	{
		// initialize TaskExecutionEvaluator object:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		evaluator.setDelayedEvaluation(this.delayInterval);
		
		var isAccepting:Boolean = true;
		var preconditionsManager:IPreconditionsManager 
			= new PreconditionsManager(isAccepting);
		
		var eventSource1:FictiveTask = new FictiveTask();
		var precondition1:EventDescriptor = new EventDescriptor(
				eventSource1, 
				"start");
		
		var eventSource2:FictiveTask = new FictiveTask();
		var precondition2:EventDescriptor = new EventDescriptor(
				eventSource2, 
				"start");
		
		preconditionsManager.add(precondition1);
		preconditionsManager.add(precondition2);
		
		// meet preconditions before PreconditionsTask initialization:
		eventSource1.start();
		eventSource2.start();
		
		// initialize PreconditionsTask with preconditionsManager:
		var preconditionsTask:ITask 
			= new PreconditionsTask(preconditionsManager);
		preconditionsTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		preconditionsTask.addEventListener(
				"completed", 
				Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		preconditionsTask.start();
		
		evaluator.registerRequiredTaskStatus({task:preconditionsTask, event:"start"});
		evaluator.registerRequiredTaskStatus({task:preconditionsTask, event:"completed"});
		
		evaluator.pauseToEvaluateTaskExecution();
	}
	
	public function testCompletedWhenStartedPrecondtionsMetAfterInitialization()
	{
		// initialize TaskExecutionEvaluator object:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		evaluator.setDelayedEvaluation(this.delayInterval);
		
		var isAccepting:Boolean = true;
		var preconditionsManager:IPreconditionsManager 
			= new PreconditionsManager(isAccepting);
		
		var eventSource1:FictiveTask = new FictiveTask();
		var precondition1:EventDescriptor = new EventDescriptor(
				eventSource1, 
				"start");
		
		var eventSource2:FictiveTask = new FictiveTask();
		var precondition2:EventDescriptor = new EventDescriptor(
				eventSource2, 
				"start");
		
		preconditionsManager.add(precondition1);
		preconditionsManager.add(precondition2);
		
		// initialize PreconditionsTask with preconditionsManager:
		var preconditionsTask:PreconditionsTask 
			= new PreconditionsTask(preconditionsManager);
		preconditionsTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		preconditionsTask.addEventListener(
				"completed", 
				Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		// meet preconditions after PreconditionsTask initialization:
		eventSource1.start();
		eventSource2.start();
		
		preconditionsTask.start();
		
		evaluator.registerRequiredTaskStatus({task:preconditionsTask, event:"start"});
		evaluator.registerRequiredTaskStatus({task:preconditionsTask, event:"completed"});
		
		evaluator.pauseToEvaluateTaskExecution();
	}
	
	public function testCompletedWhenStartedPrecondtionsMetAfterStart()
	{
		// initialize TaskExecutionEvaluator object:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		evaluator.setDelayedEvaluation(this.delayInterval);
		
		var isAccepting:Boolean = true;
		var preconditionsManager:IPreconditionsManager 
			= new PreconditionsManager(isAccepting);
		
		var eventSource1:FictiveTask = new FictiveTask();
		var precondition1:EventDescriptor = new EventDescriptor(
				eventSource1, 
				"start");
		preconditionsManager.add(precondition1);
		
		var eventSource2:FictiveTask = new FictiveTask();
		var precondition2:EventDescriptor = new EventDescriptor(
				eventSource2, 
				"start");
		preconditionsManager.add(precondition2);
		
		// initialize PreconditionsTask with preconditionsManager:
		var preconditionsTask:ITask 
			= new PreconditionsTask(preconditionsManager);
		preconditionsTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		preconditionsTask.addEventListener(
				"completed", 
				Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		preconditionsTask.start();
		evaluator.registerRequiredTaskStatus({task:preconditionsTask, event:"start"});
		
		// meet preconditions after PreconditionsTask start:
		eventSource1.start();
		// start event has been raised, but completed event has not yet:
		evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister("preconditionsTask was started, but preconditionsTask should not be completed(only precondition1 was met)");
		
		eventSource2.start();
		evaluator.registerRequiredTaskStatus({task:preconditionsTask, event:"completed"});
		
		evaluator.pauseToEvaluateTaskExecution();
	}
	
	public function testCompletedWhenStartedPreconditionsNotMet()
	{
		// initialize TaskExecutionEvaluator object:
		var evaluator:TaskExecutionEvaluator = new TaskExecutionEvaluator(this);
		evaluator.setDelayedEvaluation(this.delayInterval);
		
		var isAccepting:Boolean = true;
		var preconditionsManager:IPreconditionsManager 
			= new PreconditionsManager(isAccepting);
		
		var eventSource1:FictiveTask = new FictiveTask();
		var precondition1:EventDescriptor = new EventDescriptor(
				eventSource1, 
				"start");
		preconditionsManager.add(precondition1);
		
		var eventSource2:FictiveTask = new FictiveTask();
		var precondition2:EventDescriptor = new EventDescriptor(
				eventSource2, 
				"start");
		preconditionsManager.add(precondition2);
		
		// initialize PreconditionsTask with preconditionsManager:
		var preconditionsTask:ITask 
			= new PreconditionsTask(preconditionsManager);
		preconditionsTask.addEventListener(
				"start", 
				Delegate.create(evaluator, evaluator.onTaskStarted));
		preconditionsTask.addEventListener(
				"completed", 
				Delegate.create(evaluator, evaluator.onTaskCompleted));
		
		preconditionsTask.start();
		evaluator.registerRequiredTaskStatus({task:preconditionsTask, event:"start"});
		
		// meet only one of the preconditions (the other precondition is still 
		// waiting to be met):
		eventSource1.start();
		
		evaluator.pauseToEvaluateTaskExecution();
		
		// start event has been raised, but completed event has not yet
		// (precondition2 has not been met yet):
		evaluator.assertTaskStatusRegisterEqualsRequiredTaskStatusRegister("preconditionsTask was started, but preconditionsTask should not be completed(only precondition1 was met)");
	}
	
	public function testIsImmediatelyInterruptable()
	{
		var isAccepting:Boolean = true;
		var preconditionsManager:IPreconditionsManager 
			= new PreconditionsManager(isAccepting);
		
		// initialize PreconditionsTask with preconditionsManager:
		var preconditionsTask:ITask 
			= new PreconditionsTask(preconditionsManager);
		
		assertTrue(
				"PreconditionsTask should be immediately interruptable", 
				preconditionsTask.isImmediatelyInterruptable());
	}
	
	public function testInterrupt()
	{
		// initialize TaskExecutionEvaluator objects:
		var evaluatorBeforeInterrupt:TaskExecutionEvaluator 
			= new TaskExecutionEvaluator(this);
		var evaluatorAfterInterrupt:TaskExecutionEvaluator 
			= new TaskExecutionEvaluator(this);
		
		// test portion before interrupt:
		evaluatorBeforeInterrupt.setDelayedEvaluation(this.delayInterval);
		
		var isAccepting:Boolean = true;
		var preconditionsManager:IPreconditionsManager 
			= new PreconditionsManager(isAccepting);
		
		// initialize PreconditionsTask with preconditionsManager:
		var preconditionsTask:PreconditionsTask
			= new PreconditionsTask(preconditionsManager);
		preconditionsTask.addEventListener(
				"start", 
				Delegate.create(
						evaluatorBeforeInterrupt, 
						evaluatorBeforeInterrupt.onTaskStarted));
		preconditionsTask.addEventListener(
				"interrupted", 
				Delegate.create(
						evaluatorBeforeInterrupt, 
						evaluatorBeforeInterrupt.onTaskInterrupted));
		
		var eventSource1:FictiveTask = new FictiveTask();
		var precondition1:EventDescriptor = new EventDescriptor(
				eventSource1, 
				"start");
		
		var eventSource2:FictiveTask = new FictiveTask();
		var precondition2:EventDescriptor = new EventDescriptor(
				eventSource2, 
				"start");
		
		preconditionsTask.add(precondition1);
		preconditionsTask.add(precondition2);
		
		preconditionsTask.start();
		evaluatorBeforeInterrupt.registerRequiredTaskStatus(
				{task:preconditionsTask, event:"start"});
		
		preconditionsTask.interrupt();
		evaluatorBeforeInterrupt.registerRequiredTaskStatus(
				{task:preconditionsTask, event:"interrupted"});
		
		evaluatorBeforeInterrupt.pauseToEvaluateTaskExecution();
		
		// test portion after interrupt:
		evaluatorAfterInterrupt.setDelayedEvaluation(this.delayInterval);
		
		preconditionsTask.addEventListener(
				"start", 
				Delegate.create(
						evaluatorAfterInterrupt, 
						evaluatorAfterInterrupt.onTaskStarted));
		preconditionsTask.addEventListener(
				"completed", 
				Delegate.create(
						evaluatorAfterInterrupt, 
						evaluatorAfterInterrupt.onTaskCompleted));
		
		// meet all preconditions after interrupt, preconditionsTask should not 
		// complete, because after interupt preconditionsTask should be started 
		// again:
		eventSource1.start();
		eventSource2.start();
		evaluatorAfterInterrupt.assertTaskStatusRegisterIsEmpty("preconditions were met after interrupt, but preconditionsTask should not be completed yet, because it's not started again");
		
		// restarting preconditionsTask after interrupt:
		preconditionsTask.start();
		evaluatorAfterInterrupt.registerRequiredTaskStatus(
				{task:preconditionsTask, event:"start"});
		
		// meet all preconditions again:
		eventSource1.start();
		eventSource2.start();
		
		evaluatorAfterInterrupt.registerRequiredTaskStatus(
				{task:preconditionsTask, event:"completed"});
		
		evaluatorAfterInterrupt.pauseToEvaluateTaskExecution();
	}
}